package pres.liko.iot.blackip.service.impl;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.data.relational.core.query.Update;
import org.springframework.stereotype.Service;
import pres.liko.iot.api.CacheOpenfrignClient;
import pres.liko.iot.bean.R;
import pres.liko.iot.bean.Validates;
import pres.liko.iot.blackip.events.BlackIpChangeEvent;
import pres.liko.iot.blackip.pojo.Dc3BlackIp;
import pres.liko.iot.blackip.service.BlackIpService;
import pres.liko.iot.utils.SnowFlakeUtil;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName: BlackIpServiceImpl
 * @Auther: liko
 * @Description:
 * @Date: 2022/11/1 16:40
 */
@Service
public class BlackIpServiceImpl implements BlackIpService {

    private R2dbcEntityTemplate r2dbcEntityTemplate;
    private ApplicationContext context;

    private CacheOpenfrignClient cacheOpenfrignClient;

    @Autowired
    public BlackIpServiceImpl(R2dbcEntityTemplate r2dbcEntityTemplate, ApplicationContext context) {
        this.r2dbcEntityTemplate = r2dbcEntityTemplate;
        this.context = context;
    }

    /**
     * 要求ip不能为空，符合ip的规范
     * 符合要求的ip就添加，不符合就返回错误数据
     *
     * @param blackIpMono
     * @return
     */
    @Override
    public Mono<R<Object>> addIp(Mono<Dc3BlackIp> blackIpMono) {
        return blackIpMono.filter(
                dc3BlackIp -> StringUtils.isNotBlank(dc3BlackIp.getIp()) && dc3BlackIp.getIp().matches(Validates.IP_REG.getStr())
        ).flatMap(dc3BlackIp -> {
            //TODO 类名和表名不匹配添加方式

            // return r2dbcEntityTemplate.insert(Dc3BlackIp.class)
            //         .into("dc3_black_ip")
            //         .using(dc3BlackIp)
            //         .map(dc3BlackIp1 -> R.ok());

            /*
             *TODO  不从数据库中取，从redis中取出
             *      如果redis不存在怎么办，虽然启动的时候会从数据库里查询然后添加没有
             *      但是如果数据库里面也没有，查出来的是空，怎么添加到redis里面
             * */
            // Mono<Boolean> booleanMono = cacheOpenfrignClient.sIsMember(Validates.IPS.getStr(), dc3BlackIp.getIp());
            // return Mono.just(dc3BlackIp)
            //         .filter(dc3BlackIp1 -> !booleanMono.block())
            //         .flatMap(dc3BlackIp1 -> {
            //             dc3BlackIp.setId(SnowFlakeUtil.getSnowFlakeId().toString());
            //             dc3BlackIp.setCreateTime(LocalDateTime.now());
            //             dc3BlackIp.setUpdateTime(LocalDateTime.now());
            //             return r2dbcEntityTemplate.insert(dc3BlackIp)
            //                     .map(dc3BlackIpSql -> {
            //                         // 发送BlackIpChangeEvent事件
            //                         context.publishEvent(new BlackIpChangeEvent());
            //                         return R.ok();
            //                     })
            //                     .defaultIfEmpty(R.fail("添加失败"));
            //         }).defaultIfEmpty(R.fail("ip已存在"));

            return cacheOpenfrignClient.sIsMember(Validates.IPS.getStr(), dc3BlackIp.getIp())
                    .map(aBoolean -> !aBoolean)
                    .flatMap(aBoolean -> {
                        System.out.println(aBoolean);
                        dc3BlackIp.setId(SnowFlakeUtil.getSnowFlakeId().toString());
                        dc3BlackIp.setCreateTime(LocalDateTime.now());
                        dc3BlackIp.setUpdateTime(LocalDateTime.now());
                        return r2dbcEntityTemplate.insert(dc3BlackIp)
                                .map(dc3BlackIpSql -> {
                                    // 发送BlackIpChangeEvent事件
                                    context.publishEvent(new BlackIpChangeEvent());
                                    return R.ok();
                                })
                                .defaultIfEmpty(R.fail("添加失败"));
                    })
                    .defaultIfEmpty(R.fail("ip已存在"));

            // 从数据库中查询是否存在
            // return r2dbcEntityTemplate.select(Dc3BlackIp.class)
            //         .from("dc3_black_ip")
            //         .matching(Query.query(Criteria.where("ip").is(dc3BlackIp.getIp())))
            //         .all()
            //         .count()
            //         .filter(aLong -> aLong == 0)
            //         .flatMap(dc3BlackIp1 -> {
            //             System.out.println(dc3BlackIp1);
            //             return r2dbcEntityTemplate.insert(dc3BlackIp)
            //                     .map(dc3BlackIpSql -> {
            //                         // 发送BlackIpChangeEvent事件
            //                         context.publishEvent(new BlackIpChangeEvent());
            //                         return R.ok();
            //                     })
            //                     .defaultIfEmpty(R.fail("添加失败"));
            //         })
            //         .defaultIfEmpty(R.fail("ip已存在"));

        }).defaultIfEmpty(R.fail("ip不符合要求"));
    }

    @Override
    public Mono<R<Set<String>>> findAllEnable() {
        return r2dbcEntityTemplate.select(
                Query.query(
                        Criteria.where("enable").is(1)
                                .and("deleted").is(0)
                ).columns("ip"), Dc3BlackIp.class)
                .map(Dc3BlackIp::getIp)
                .collect(Collectors.toSet())
                .map(dc3BlackIps -> R.ok(dc3BlackIps))
                .defaultIfEmpty(R.fail("无数据"));
    }

    @Override
    public Mono<R<Object>> deleteIp(String id) {
        return r2dbcEntityTemplate.select(Dc3BlackIp.class)
                .from("dc3_black_ip")
                .matching(Query.query(Criteria.where("id").is(id)))
                .first()
                .flatMap(dc3BlackIp -> {
                    return r2dbcEntityTemplate
                            .delete(Dc3BlackIp.class)
                            .from("dc3_black_ip")
                            .matching(Query.query(Criteria.where("id").is(id)))
                            .all()
                            .filter(integer -> integer > 0)
                            .map(integer -> {
                                context.publishEvent(new BlackIpChangeEvent());
                                return R.ok();
                            })
                            .defaultIfEmpty(R.fail("删除失败"));
                }).defaultIfEmpty(R.fail("id不存在"));
    }

    @Override
    public Mono<R<Object>> updateEnableById(String id, Integer enable) {
        return r2dbcEntityTemplate.select(Dc3BlackIp.class)
                .from("dc3_black_ip")
                .matching(Query.query(Criteria.where("id").is(id)))
                .first()
                .flatMap(dc3BlackIp -> {
                    return r2dbcEntityTemplate
                            .update(Dc3BlackIp.class)
                            .inTable("dc3_black_ip")
                            .matching(Query.query(Criteria.where("id").is(id)))
                            .apply(Update.update("enable", enable))
                            .filter(integer -> integer > 0)
                            .map(integer -> {
                                context.publishEvent(new BlackIpChangeEvent());
                                return R.ok();
                            })
                            .defaultIfEmpty(R.fail("修改失败"));
                }).defaultIfEmpty(R.fail("id不存在"));

    }

    @Override
    public Mono<R<Object>> updateDeletedById(String id) {
        return r2dbcEntityTemplate.select(Dc3BlackIp.class)
                .from("dc3_black_ip")
                .matching(Query.query(Criteria.where("id").is(id)))
                .first()
                .flatMap(dc3BlackIp -> {
                    return r2dbcEntityTemplate
                            .update(Dc3BlackIp.class)
                            .inTable("dc3_black_ip")
                            .matching(Query.query(Criteria.where("id").is(id)))
                            .apply(Update.update("deleted", 1)
                            ).filter(integer -> integer > 0)
                            .map(integer -> {
                                context.publishEvent(new BlackIpChangeEvent());
                                return R.ok();
                            })
                            .defaultIfEmpty(R.fail("修改失败"));
                }).defaultIfEmpty(R.fail("id不存在"));
    }

    @Override
    public Mono<R<Object>> updateIp(Mono<Dc3BlackIp> blackIpMono) {
        return blackIpMono.filter(
                dc3BlackIp -> StringUtils.isNotBlank(dc3BlackIp.getIp()) && dc3BlackIp.getIp().matches(Validates.IP_REG.getStr())
        ).doOnNext(dc3BlackIp -> {
            dc3BlackIp.setUpdateTime(LocalDateTime.now());
        }).flatMap(dc3BlackIp -> {
            return r2dbcEntityTemplate.update(Dc3BlackIp.class)
                    .inTable("dc3_black_ip")
                    .matching(Query.query(Criteria.where("id").is(dc3BlackIp.getId())))
                    .apply(Update.update("ip", dc3BlackIp.getIp())
                            .set("description", dc3BlackIp.getDescription())
                            .set("update_time", LocalDateTime.now())
                    )
                    .filter(integer -> integer > 0)
                    .map(integer -> {
                        context.publishEvent(new BlackIpChangeEvent());
                        return R.ok();
                    })
                    .defaultIfEmpty(R.fail("修改失败"));
        }).defaultIfEmpty(R.fail("ip不符合要求"));
    }
}
